/**
 *    Copyright 2012 Geensoft S.A.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package ar.com.greensoft.neosystem.crm.web.beans;

import java.security.Principal;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.ManagedBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import ar.com.greensoft.jeecommons.web.jsf.util.JSFMenuUtil;
import ar.com.greensoft.neosystem.dao.UserDao;
import ar.com.greensoft.neosystem.model.User;
import ar.com.greensoft.neosystem.util.ApplicationRoles;

import java.io.IOException;
import java.io.Serializable;

/**
 * @author Jorge E. Villaverde
 * @date 08/07/2011
 * @version 1.0.0
 */
@SessionScoped
@ManagedBean
@Named
public class HomeBean implements Serializable, ApplicationRoles, NavigationConstants {
	private static final String REMEMBER_ME_COOKIE_NAME = "NeoRememberMe";
	private static final String PASSWORD_COOKIE_NAME = "NeoPassword";
	private static final String USERNAME_COOKIE_NAME = "NeoUsername";

	/**
	 * 
	 */
	private static final long serialVersionUID = -1300766856084221757L;
	private static final String HOME_PATH = "home.jsf";
	private static final String ADMIN_HOME_PATH = "admin";
	private static final String USER_HOME_PATH = "user";
	private static final String LOGIN_PAGE = "login.jsf";
	private static final String LOGIN_ERROR_PAGE = "login.jsf";

	
	@Inject
	private Logger logger;

	private String username;
	private String password;
	private boolean rememberMe;

	private User user;
	private String currentGroup;

	private boolean authenticationError;
		
	@EJB
	private UserDao userDao;

	private static Map<String, String> rolesHomeMap;

	static {
		rolesHomeMap = new WeakHashMap<String, String>();

		rolesHomeMap.put(ROLE_ADMIN, makeHomeAction(ADMIN_HOME_PATH));
		rolesHomeMap.put(ROLE_USER, makeHomeAction(USER_HOME_PATH));
	}

	public String getUserHome() {

		return HOME_PATH;
	}

	@PostConstruct
	public void initialize() {
		this.authenticationError = false;
		checkCookie();
	}

	@PreDestroy
	public void preDestroy() {
	}

	private String getNoExternaContextHome() {
		String homePage = null;

		if (this.currentGroup != null) {
			homePage = rolesHomeMap.get(currentGroup);
		}
		if (homePage == null) {
			if (isAdministrador()) {
				homePage = rolesHomeMap.get(ROLE_ADMIN);
			} else if (isUser()) {
				homePage = rolesHomeMap.get(ROLE_USER);
			}
		}
		if (StringUtils.isEmpty(homePage)) {
			homePage = PATH_SEPARATOR + LOGIN_PAGE;
		}
		return homePage + JSFMenuUtil.JSF_REDIRECT_ESCAPED;
	}

	public String getHome() {
		StringBuilder builder = new StringBuilder();

		String homePage = getNoExternaContextHome();
		ExternalContext ec = FacesContext.getCurrentInstance()
				.getExternalContext();

		builder.append(ec.getRequestContextPath());
		builder.append(homePage);
		if (logger.isLoggable(Level.FINE))
			logger.fine("URL: " + builder.toString());

		return builder.toString();
	}

	private boolean isUserInRole(String role) {
		FacesContext context = FacesContext.getCurrentInstance();
		HttpServletRequest request = (HttpServletRequest) context
				.getExternalContext().getRequest();
		return request.isUserInRole(role);
	}

	private boolean isAdministrador() {
		return isUserInRole(ROLE_ADMIN);
	}

	private boolean isUser() {
		return isUserInRole(ROLE_USER);
	}

	public String login() {
		ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
		HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
		HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
		try {
			request.login(this.username, this.password);
			this.user = userDao.findById(username);
			this.currentGroup = getUserRole();

			String returnPage = externalContext.getRequestParameterMap().get("redirect");
			
			if(StringUtils.isEmpty(returnPage) || returnPage.endsWith(LOGIN_PAGE)){
				returnPage = getNoExternaContextHome();
			}else{
				String contextName = request.getContextPath();
				if(returnPage.startsWith(contextName)){
					returnPage = returnPage.substring(contextName.length());
				}					
				returnPage += JSFMenuUtil.JSF_REDIRECT_ESCAPED;
			}
			
			// Save the userid and password in a cookie
			Cookie btuser = new Cookie(USERNAME_COOKIE_NAME, username);
			Cookie btpasswd = new Cookie(PASSWORD_COOKIE_NAME,password);
			String remember = "false";
			if(rememberMe){
				remember = "true";
			}			  
			Cookie btremember = new Cookie(REMEMBER_ME_COOKIE_NAME, remember);
			btuser.setMaxAge(3600);
			btpasswd.setMaxAge(3600);
			  
			response.addCookie(btuser);
			response.addCookie(btpasswd);
			response.addCookie(btremember);
			
			// Cargamos el Perfil del Usuario al iniciar sesión
			loadUserProfile();
			
			return returnPage;
		} catch (ServletException e) {
			request.getSession(false).invalidate();
			this.authenticationError = true;
			this.user = null;
			logger.warning("Login or password incorrect: " + username);
			return LOGIN_ERROR_PAGE;
		}catch(Exception e){
			request.getSession(false).invalidate();
			this.authenticationError = true;
			this.user = null;
			logger.warning(e.getClass().getSimpleName() + ": " + e.getMessage());
			return LOGIN_ERROR_PAGE;			
		}	
	}

	private void loadUserProfile() {
		//TODO Cargar las cookies con los valores almacenados
	}
	
	public void logout() {
		ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
		HttpServletRequest request = (HttpServletRequest) ec.getRequest();
		request.getSession(false).invalidate();
		this.user = null;
		try {
			ec.redirect(ec.getRequestContextPath() + "/" + LOGIN_PAGE);
		} catch (IOException e) {
			logger.severe("Logout error: " + e.getMessage());
		}
	}

	public void checkCookie(){
		FacesContext facesContext = FacesContext.getCurrentInstance();
		String cookieName = null;
		Cookie cookie[] = ((HttpServletRequest)facesContext.getExternalContext().getRequest()).getCookies();

		if(cookie != null && cookie.length > 0){
			 for(int i = 0; i<cookie.length; i++){
				 cookieName = cookie[i].getName();
				 if(USERNAME_COOKIE_NAME.equals(cookieName)){
					 username = cookie[i].getValue();
				 }else if(PASSWORD_COOKIE_NAME.equals(cookieName)){
					 password = cookie[i].getValue();
				 }else if(REMEMBER_ME_COOKIE_NAME.equals(cookieName)){
					 String remember1 = cookie[i].getValue();
					 if(remember1.equals("false")){
						 rememberMe = false;
					 }else if(remember1.equals("true")){
						 rememberMe = true;
					 }
				 }
			 }
		}else{
			logger.info("Cannot find any cookie");
		}
	}
	
	public boolean isAuthenticated() {
		Principal principal = FacesContext.getCurrentInstance()
				.getExternalContext().getUserPrincipal();
		return (principal != null);
	}

	public String getNombreUsuario() {
		if (isAuthenticated()) {
			Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
			if (principal != null) {
				return principal.getName();
			}
		}
		return "";
	}
	
	public String getUserRole() {
		if (isAuthenticated()) {
			if (this.currentGroup != null)
				return this.currentGroup.toString();
			if(isAdministrador()){
				return ROLE_ADMIN;
			}else if(isUser()){
				return ROLE_USER;
			}
		}
		return ROLE_ANONYMOUS;
	}
	

	public String getCurrentGroup() {
		return currentGroup;
	}

	public void setCurrentGroup(String currentGroup) {
		this.currentGroup = currentGroup;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public User getUser() {
		return user;
	}
	
	private static String makeHomeAction(String path) {
		StringBuilder builder = new StringBuilder();

		builder.append(PATH_SEPARATOR);
		builder.append(PROTECTED_PATH);
		builder.append(PATH_SEPARATOR);
		builder.append(path);
		builder.append(PATH_SEPARATOR);
		builder.append(HOME_ACTION);
		builder.append(FILE_EXT);
		
		return builder.toString();
	}

	public String showProfile(){
		return "";
	}

	public boolean isAuthenticationError() {
		return authenticationError;
	}

	public boolean isRememberMe() {
		return rememberMe;
	}

	public void setRememberMe(boolean rememberMe) {
		this.rememberMe = rememberMe;
	}
}
